package com.jzo2o.foundations.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.*;
import com.jzo2o.foundations.model.domain.*;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author itlxc
 * @since 2024-10-11
 */
@Service
@RequiredArgsConstructor
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {

    private final ServeMapper serveMapper;

    private final IServeItemService serveItemService;

    private final IRegionService regionService;

    private final RegionMapper regionMapper;

    private final ServeItemMapper serveItemMapper;

    private final ServeTypeMapper serveTypeMapper;

    private final ServeSyncMapper serveSyncMapper;

    /**
     * 分页查询
     *
     * @param servePageQueryReqDTO 查询条件
     * @return 分页结果
     */
    @Override
    public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
        return PageHelperUtils.selectPage(servePageQueryReqDTO, () -> serveMapper.queryServeListByRegionId(servePageQueryReqDTO.getRegionId()));
    }

    /**
     * 批量新增服务
     * @param serveUpsertReqDTOS
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBatch(List<ServeUpsertReqDTO> serveUpsertReqDTOS) {
        // 1.校验服务项是否为启用状态，不是启用状态不能新增
        Set<Long> serveItemIds = serveUpsertReqDTOS.stream()
                .map(ServeUpsertReqDTO::getServeItemId)
                .collect(Collectors.toSet());
        List<ServeItem> serveItemList = serveItemService.lambdaQuery().in(ServeItem::getId, serveItemIds).list();
        if (CollUtil.isEmpty(serveItemList)) {
            throw new ForbiddenOperationException("服务项不存在");
        }
        serveItemList.forEach(serveItem -> {
            if (serveItem.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
                throw new ForbiddenOperationException("该服务项未启用无法添加到区域下使用");
            }
        });

        // 2.校验是否重复新增
        serveUpsertReqDTOS.forEach(serveUpsertReqDTO -> {
            Integer count = this.lambdaQuery().eq(Serve::getRegionId, serveUpsertReqDTO.getRegionId())
                    .eq(Serve::getServeItemId, serveUpsertReqDTO.getServeItemId())
                    .count();
            if (count > 0) {
                throw new ForbiddenOperationException("该服务已存在");
            }
        });
        // 3.新增服务
        Set<Long> regionIds = serveUpsertReqDTOS.stream().map(ServeUpsertReqDTO::getRegionId).collect(Collectors.toSet());
        List<Region> regionList = regionService.lambdaQuery().in(Region::getId, regionIds).list();
        Map<Long, String> map = new HashMap<>();
        if (CollUtil.isNotEmpty(regionList)) {
            map = regionList.stream().collect(Collectors.toMap(Region::getId, Region::getCityCode, (k1, k2) -> k1));
        }
        List<Serve> serveList = BeanUtil.copyToList(serveUpsertReqDTOS, Serve.class);
        Map<Long, String> finalMap = map;
        serveList.forEach(serve -> serve.setCityCode(finalMap.get(serve.getRegionId())));
        boolean flag = this.saveBatch(serveList);
        if (!flag) {
            throw new ForbiddenOperationException("新增服务失败");
        }
    }

    /**
     * 修改服务价格
     * @param id
     * @param price
     */
    @Override
    public void updatePrice(Long id, BigDecimal price) {
        boolean flag = this.lambdaUpdate().set(Serve::getPrice, price).eq(Serve::getId, id).update();
        if (!flag) {
            throw new ForbiddenOperationException("修改服务价格失败");
        }
    }

    /**
     * 上架服务
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")
    public void onSale(Long id) {
        Serve serve = this.getById(id);
        if (ObjectUtil.isNull(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        // 判断区域服务当前状态是否为草稿或下架
        Integer status = serve.getSaleStatus();
        if (!(FoundationStatusEnum.INIT.getStatus() == status || FoundationStatusEnum.DISABLE.getStatus() == status)) {
            throw new ForbiddenOperationException("只有草稿或下架的服务才能上架");
        }
        // 判断服务项是否启用
        ServeItem serveItem = serveItemService.getById(serve.getServeItemId());
        if (ObjectUtil.isNull(serveItem)) {
            throw new ForbiddenOperationException("所属服务项不存在");
        }
        if (serveItem.getActiveStatus() != FoundationStatusEnum.DISABLE.getStatus()) {
            throw new ForbiddenOperationException("服务项为禁用状态方可上架");
        }
        boolean flag = this.lambdaUpdate().set(Serve::getSaleStatus, FoundationStatusEnum.ENABLE.getStatus())
                .eq(Serve::getId, id).update();
        if (!flag) {
            throw new ForbiddenOperationException("服务上架失败");
        }
        addServeSync(id);
    }

    /**
     * 删除服务
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")
    public void delete(Long id) {
        Serve serve = this.getById(id);
        if (ObjectUtil.isNull(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        // 判断状态是否为草稿
        if (!(FoundationStatusEnum.INIT.getStatus() == serve.getSaleStatus())) {
            throw new ForbiddenOperationException("只有草稿的服务才能删除");
        }
        if (!this.removeById(id)) {
            throw new ForbiddenOperationException("服务删除失败");
        }
    }

    /**
     * 下架服务
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")
    public void offSale(Long id) {
        Serve serve = this.getById(id);
        if (ObjectUtil.isNull(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        // 判断状态是否为启用
        if (!(FoundationStatusEnum.ENABLE.getStatus() == serve.getSaleStatus())) {
            throw new ForbiddenOperationException("只有启用的服务才能下架");
        }
        ServeItem serveItem = serveItemService.getById(serve.getServeItemId());
        if (ObjectUtil.isNull(serveItem)) {
            throw new ForbiddenOperationException("所属服务项不存在");
        }
        // 判断服务项是否启用
        if (serveItem.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            throw new ForbiddenOperationException("服务项为启用状态方可下架");
        }
        boolean flag = this.lambdaUpdate().set(Serve::getSaleStatus, FoundationStatusEnum.DISABLE.getStatus())
                .eq(Serve::getId, id).update();
        if (!flag) {
            throw new ForbiddenOperationException("服务下架失败");
        }
    }

    /**
     * 设为热门
     * @param id
     */
    @Override
    public void onHot(Long id) {
        Serve serve = this.getById(id);
        if (ObjectUtil.isNull(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        if (!(FoundationStatusEnum.ENABLE.getStatus() == serve.getSaleStatus())) {
            throw new ForbiddenOperationException("只有启用的服务才能设为热门");
        }
        if (serve.getIsHot() != 0) {
            throw new ForbiddenOperationException("该服务已设为热门");
        }
        boolean flag = this.lambdaUpdate().set(Serve::getIsHot, 1).set(Serve::getHotTimeStamp, System.currentTimeMillis())
                .eq(Serve::getId, id).update();
        if (!flag) {
            throw new ForbiddenOperationException("设为热门失败");
        }
    }

    /**
     * 取消设为热门
     * @param id
     */
    @Override
    public void offHot(Long id) {
        Serve serve = this.getById(id);
        if (ObjectUtil.isNull(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        if (!(FoundationStatusEnum.ENABLE.getStatus() == serve.getSaleStatus())) {
            throw new ForbiddenOperationException("只有启用的服务才能取消热门");
        }
        if (serve.getIsHot() != 1) {
            throw new ForbiddenOperationException("该服务未设为热门");
        }
        boolean flag = this.lambdaUpdate().set(Serve::getIsHot, 0).set(Serve::getHotTimeStamp, System.currentTimeMillis())
                .eq(Serve::getId, id).update();
        if (!flag) {
            throw new ForbiddenOperationException("取消设为热门失败");
        }
    }

    /**
     * 新增服务同步数据
     *
     * @param serveId 服务id
     */
    private void addServeSync(Long serveId) {
        //服务信息
        Serve serve = baseMapper.selectById(serveId);
        //区域信息
        Region region = regionMapper.selectById(serve.getRegionId());
        //服务项信息
        ServeItem serveItem = serveItemMapper.selectById(serve.getServeItemId());
        //服务类型
        ServeType serveType = serveTypeMapper.selectById(serveItem.getServeTypeId());

        ServeSync serveSync = new ServeSync();
        serveSync.setServeTypeId(serveType.getId());
        serveSync.setServeTypeName(serveType.getName());
        serveSync.setServeTypeIcon(serveType.getServeTypeIcon());
        serveSync.setServeTypeImg(serveType.getImg());
        serveSync.setServeTypeSortNum(serveType.getSortNum());

        serveSync.setServeItemId(serveItem.getId());
        serveSync.setServeItemIcon(serveItem.getServeItemIcon());
        serveSync.setServeItemName(serveItem.getName());
        serveSync.setServeItemImg(serveItem.getImg());
        serveSync.setServeItemSortNum(serveItem.getSortNum());
        serveSync.setUnit(serveItem.getUnit());
        serveSync.setDetailImg(serveItem.getDetailImg());
        serveSync.setPrice(serve.getPrice());

        serveSync.setCityCode(region.getCityCode());
        serveSync.setId(serve.getId());
        serveSync.setIsHot(serve.getIsHot());
        serveSyncMapper.insert(serveSync);
    }
}
